

#include "meetinghandler.h"
#include "package.h"


UserList::UserList()
{
	sp_thread_mutex_init( &mMutex, NULL );
}

UserList :: ~UserList()
{
	sp_thread_mutex_destroy( &mMutex );
}

void UserList :: copy( SP_SidList * outList, SP_Sid_t * ignoreSid )
{
	sp_thread_mutex_lock( &mMutex );

	for( int i = 0; i < mList.getCount(); i++ ) {
		if( NULL != ignoreSid ) {
			SP_Sid_t theSid = mList.get( i );
			if( theSid.mKey == ignoreSid->mKey && theSid.mSeq == ignoreSid->mSeq ) {
				continue;
			}
		}

		outList->add( mList.get( i ) );
	}

	sp_thread_mutex_unlock( &mMutex );
}

void UserList :: remove( SP_Sid_t sid )
{
	sp_thread_mutex_lock( &mMutex );

	for( int i = 0; i < mList.getCount(); i++ ) {
		SP_Sid_t theSid = mList.get( i );
		if( theSid.mKey == sid.mKey && theSid.mSeq == sid.mSeq ) {
			mList.take( i );
			break;
		}
	}

	sp_thread_mutex_unlock( &mMutex );
}

void UserList :: add( SP_Sid_t sid )
{
	sp_thread_mutex_lock( &mMutex );

	mList.add( sid );

	sp_thread_mutex_unlock( &mMutex );
}

int UserList :: getCount()
{
	int count = 0;

	sp_thread_mutex_lock( &mMutex );

	count = mList.getCount();

	sp_thread_mutex_unlock( &mMutex );

	return count;
}
MeetingInfo::MeetingInfo()
{
	sp_thread_mutex_init(&mMutex,NULL);
	desktopShared=false;
}
MeetingInfo::~MeetingInfo()
{
	std::map<int,UserInfo*>::iterator it=mUserInfoList.begin();
	while(it!=mUserInfoList.end())
	{
		delete it->second;
		it++;
	}
	mUserInfoList.clear();
	sp_thread_mutex_destroy(&mMutex);
}
bool MeetingInfo::setSharer(SP_Sid_t sharer,Meeting::ShareType shareType)
{
	bool ret=false;
	sp_thread_mutex_lock(&mMutex);
	if(shareType==Meeting::ShareType::DESKTOP || shareType==Meeting::ShareType::APPLICATION)
	{
		if(!desktopShared)
		{
			desktopShared=true;
			mDesktopSharer=sharer;
			ret=true;
		}
	}
	else if(shareType==Meeting::ShareType::WHITEBOARD)
	{
		mWhiteboardShareUsers.add(sharer);
		ret=true;
	}
	sp_thread_mutex_unlock(&mMutex);
	return ret;
}
void MeetingInfo::add(SP_Sid_t attender,Meeting::LoginRequest* request)
{
	sp_thread_mutex_lock(&mMutex);
	UserInfo* info=mUserInfoList[attender.mKey];
	if(info!=NULL)
	{
		delete info;
		mUserInfoList[attender.mKey]=NULL;
	}
	info=new UserInfo();
	info->meetingId=request->meetingid();
	info->name=request->name();
	info->password=request->password();
	info->sid=attender;
	info->terminalType=request->terminaltype();
	mUserInfoList[attender.mKey]=info;
	sp_thread_mutex_unlock(&mMutex);
}
void MeetingInfo::remove(SP_Sid_t attender)
{
	sp_thread_mutex_lock(&mMutex);
	UserInfo* info=mUserInfoList[attender.mKey];
	if(info!=NULL)
	{
		delete info;
		mUserInfoList.erase(attender.mKey);
		//mUserInfoList[attender.mKey]=NULL;
	}
	sp_thread_mutex_unlock(&mMutex);
}
void MeetingInfo::getUserList(SP_SidList * outList, SP_Sid_t * ignoreSid)
{
	sp_thread_mutex_lock(&mMutex);
	std::map<int,UserInfo*>::iterator it=mUserInfoList.begin();
	while(it!=mUserInfoList.end())
	{
		if(ignoreSid!=NULL)
		{
			if(it->second->sid.mKey==ignoreSid->mKey && it->second->sid.mSeq==ignoreSid->mSeq)
			{
				it++;
				continue;
			}
		}
		outList->add(it->second->sid);
		it++;
	}
	sp_thread_mutex_unlock(&mMutex);
}

MeetingManager::MeetingManager()
{
	sp_thread_mutex_init(&mMutex,NULL);
}
MeetingManager::~MeetingManager()
{
	std::map<int,MeetingInfo*>::iterator it=mMapMeeting.begin();
	while(it!=mMapMeeting.end())
	{
		delete it->second;
		it++;
	}
	sp_thread_mutex_destroy(&mMutex);
}
MeetingInfo* MeetingManager::getMeetingInfo(int meetingId)
{
	sp_thread_mutex_lock(&mMutex);
	MeetingInfo* info=mMapMeeting[meetingId];
	if(info==NULL)
	{
		info=new MeetingInfo();
		mMapMeeting[meetingId]=info;
	}
	sp_thread_mutex_unlock(&mMutex);
	return info;
}
bool MeetingManager::attendMeeting(SP_Sid_t sid,Meeting::LoginRequest* request)
{
	int meetingId=request->meetingid();
	MeetingInfo* info=getMeetingInfo(meetingId);
	info->add(sid,request);
	return true;
}
bool MeetingManager::leaveMeeting(SP_Sid_t sid,int meetingId)
{
	MeetingInfo* info=mMapMeeting[meetingId];
	if(info==NULL)
	    return false;
	info->remove(sid);
	return true;
}

int MeetingHandler :: mMsgSeq = 0;

MeetingHandler :: MeetingHandler( MeetingManager * meetingManager )
{
	memset( &mSid, 0, sizeof( mSid ) );

	mMeetingManager = meetingManager;
}

MeetingHandler :: ~MeetingHandler()
{
	
}

void MeetingHandler :: broadcast( SP_Response * response, const char * buffer,size_t size, SP_Sid_t * ignoreSid )
{
	MeetingInfo* info=mMeetingManager->getMeetingInfo(mMeetingId);
	if( info->getUserCount() > 0 ) {
		SP_Message * msg = new SP_Message();
		info->getUserList( msg->getToList(), ignoreSid );
		msg->setCompletionKey( ++mMsgSeq );

		msg->getMsg()->append( buffer ,size);
		response->addMessage( msg );
	}
}
void MeetingHandler :: broadcast( SP_Response * response, const string& msg, SP_Sid_t * ignoreSid )
{
	broadcast(response,msg.c_str(),msg.size(),ignoreSid);
}
int MeetingHandler :: start( SP_Request * request, SP_Response * response )
{
	request->setMsgDecoder( new MeetingMsgDecoder() );
	mSid = response->getFromSid();

	/*char buffer[ 128 ] = { 0 };
	snprintf( buffer, sizeof( buffer ),
		"Welcome %d to chat server, enter 'quit' to quit.\r\n", mSid.mKey );
	response->getReply()->getMsg()->append( buffer );
	response->getReply()->setCompletionKey( ++mMsgSeq );

	snprintf( buffer, sizeof( buffer ), "SYS : %d online\r\n", mSid.mKey);

	broadcast( response, buffer,strlen(buffer) );*/

	mMeetingManager->getUserList()->add( mSid );
	return 0;
}
bool messageTypeMatch(const std::string& type1,const std::string& type2)
{
	return 0==strcmp(type1.c_str(),type2.c_str());
}
void MeetingHandler :: process(Package* package, SP_Response * response)
{
	std::string msgtype=package->getMessage()->GetTypeName();
	if(messageTypeMatch(msgtype,Meeting::LoginRequest::default_instance().GetTypeName() ))
	{
		Meeting::LoginRequest* request=(Meeting::LoginRequest*)package->getMessage().get();
		mMeetingManager->attendMeeting(mSid,request);
		mMeetingId=request->meetingid();
		Meeting::LoginResponse resp;
		resp.set_result(Meeting::LoginResponse_LoginResult::LoginResponse_LoginResult_SUCCEED);
		resp.set_rights(0);
		resp.set_meetingid(mMeetingId);
		resp.set_session(mSid.mKey);
		resp.set_errormsg("");
		std::string msg;
		MessageUtil::serializePackageToString(resp,package->getSerialNum(),&msg);
		response->getReply()->getMsg()->append(msg.c_str(),msg.size());
		response->getReply()->setCompletionKey( ++mMsgSeq );
		printf("User Login:%s\r\n",request->ShortDebugString().c_str());

		
	}
	else if(messageTypeMatch(msgtype,Meeting::ShareRequest::default_instance().GetTypeName() ))
	{
		Meeting::ShareRequest* request=(Meeting::ShareRequest*)package->getMessage().get();
		MeetingInfo* info=mMeetingManager->getMeetingInfo(mMeetingId);
		bool ok=info->setSharer(mSid,request->sharetype());
		
		Meeting::ShareResponse resp;
		if(ok)
		{
		    resp.set_result(Meeting::ShareResponse_ShareResult::ShareResponse_ShareResult_SUCCEED);
		    resp.set_errormsg("");
		}
		else
		{
			resp.set_result(Meeting::ShareResponse_ShareResult::ShareResponse_ShareResult_FAILED);
			std::string error("someone has shared");
		    resp.set_errormsg(error);
		}
		std::string msg;
		MessageUtil::serializePackageToString(resp,package->getSerialNum(),&msg);
		response->getReply()->getMsg()->append(msg.c_str(),msg.size());
		response->getReply()->setCompletionKey( ++mMsgSeq );
		printf("User[%d] Share Apply:%s\r\n",response->getFromSid().mKey,request->ShortDebugString().c_str());
	}
	else if(messageTypeMatch(msgtype,Meeting::PublishData::default_instance().GetTypeName() ))
	{
		Meeting::PublishData* request=(Meeting::PublishData*)package->getMessage().get();
		std::string msg;
		MessageUtil::serializePackageToString(*request,package->getSerialNum(),&msg);
		broadcast(response,msg.c_str(),msg.size(),&mSid);
		printf("User[%d] Share Data:%s\r\n",response->getFromSid().mKey,request->ShortDebugString().c_str());
	}
}

int MeetingHandler :: handle( SP_Request * request, SP_Response * response )
{
	MeetingMsgDecoder * decoder = (MeetingMsgDecoder*)request->getMsgDecoder();
	SP_CircleQueue * msgQueue = decoder->getQueue();

	char buffer[ 256 ] = { 0 };
	int ret = 0;

	for( ; NULL != msgQueue->top(); ) {
		Package * package = (Package*)msgQueue->pop();
		process(package,response);
		free( package );
	}

	return ret;
}

void MeetingHandler :: error( SP_Response * response )
{
	char buffer[ 64 ] = { 0 };
	snprintf( buffer, sizeof( buffer ), "SYS : %d error offline\r\n", mSid.mKey );

	broadcast( response, buffer, strlen(buffer),&mSid );
}

void MeetingHandler :: timeout( SP_Response * response )
{
	char buffer[ 64 ] = { 0 };
	snprintf( buffer, sizeof( buffer ), "SYS : %d timeout offline\r\n", mSid.mKey );

	broadcast( response, buffer,strlen(buffer), &mSid );
}

void MeetingHandler :: close()
{
	mMeetingManager->getUserList()->remove( mSid );
	mMeetingManager->leaveMeeting(mSid,mMeetingId);
}


void MeetingCompletionHandler :: completionMessage( SP_Message * msg )
{
#if 0
	printf( "message completed { completion key : %d }\n", msg->getCompletionKey() );

	printf( "\tsuccess {" );
	for( int i = 0; i < msg->getSuccess()->getCount(); i++ ) {
		printf( " %d", msg->getSuccess()->get( i ).mKey );
	}
	printf( "}\n" );

	printf( "\tfailure {" );
	for( int i = 0; i < msg->getFailure()->getCount(); i++ ) {
		printf( " %d", msg->getFailure()->get( i ).mKey );
	}
	printf( "}\n" );
#endif

	delete msg;
}